#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>

#include "slowcat.h"

struct job_st {
	int cps;
	int token;
	int burst;
	int pos;
	pthread_mutex_t mutex; 			// 定义互斥量，避免操作token的时候错误
};

static struct job_st *jobs[JOB_MAX];
static pthread_mutex_t mutex_job;	// 定义互斥量，避免jobs访问错误
static pthread_once_t init_once;	// 函数只调用一次
static pthread_t tid;

/*
 * 线程部分，不断的生成数据
 * */
static void * task_alrm(void *p)
{
	int i;
	while(1){
		for (i = 0; i < JOB_MAX; i++) {
			if(jobs[i] != NULL)
			{
				pthread_mutex_lock(&jobs[i]->mutex);
				jobs[i]->token += jobs[i]->cps;
				if(jobs[i]->token > jobs[i]->burst)
				{
			 		jobs[i]->token = jobs[i]->burst;	
				}
				pthread_mutex_unlock(&jobs[i]->mutex);
				sleep(1);
			}
		}
	}
}

static void module_unload(void)
{
	pthread_cancel(tid);
	pthread_join(tid, NULL);

	for (int i = 0; i < JOB_MAX; i++) {
		if(jobs[i] == NULL){
			job_destory(jobs[i]);
		}
	}
	pthread_mutex_destroy(&mutex_job);
}

static void module_load(void)
{
	int err;
	err = pthread_create(&tid, NULL, &task_alrm, NULL);
	if (err) {
		  fprintf(stderr, "pthread_create(): %s\n", strerror(err));
	}
	atexit(module_unload);
}

// 在函数名称上体现出来，该函数是没有进行加锁的，这样来告诉调用者
static int get_free_pos_unlock()
{
	for (int i = 0; i < JOB_MAX; i++) {
		if(jobs[i] == NULL)
		{
			return i;
		}
	}
	return -1;
}

job_t *job_init(int cps, int burst)
{
	struct job_st *me;
	int pos;

	pthread_once(&init_once, module_load);

	me = malloc(sizeof(*me));
	if(me == NULL)
	{
		return NULL;
	}

	me->token = 0;
	me->burst = burst;
	me->cps = cps;
	pthread_mutex_init(&me->mutex, NULL);
	
	pthread_mutex_lock(&mutex_job);
	pos = get_free_pos_unlock();
	if(pos < 0)
	{
		pthread_mutex_unlock(&mutex_job);
		free(me);
		return NULL;
	}
	me->pos = pos;
	jobs[pos] = me;
	pthread_mutex_unlock(&mutex_job);

	return me;
}

/*
 *获取令牌
 * */
int job_fetchtoken(job_t *job, int size)
{
	struct job_st *me = job;

	if(size <= 0)
	{
		return -EINVAL;
	}

	pthread_mutex_lock(&me->mutex);
	while(me->token <= 0)
	{
		pthread_mutex_unlock(&me->mutex);
		sched_yield();
		pthread_mutex_lock(&me->mutex);
	}
	int n = (me->token > size ? size : me->token);
	me->token -= n;
	pthread_mutex_unlock(&me->mutex);

	return n;
}

/*
 * 归还令牌
 * */
int job_returntoken(job_t *ptr, int size)
{
	struct job_st *me = ptr;
	if(size <= 0)
	{
		return -EINVAL;
	}
	pthread_mutex_lock(&me->mutex);
	me->token += size;
	if(me->token > me->burst)
	{
		me->token = me->burst;
	}
	pthread_mutex_unlock(&me->mutex);
	return -1;
}

/*
 * 销毁单个job
 * */
int job_destory(job_t *ptr)
{
	struct job_st *me = ptr;

	pthread_mutex_lock(&mutex_job);
	jobs[me->pos] = NULL;
	pthread_mutex_unlock(&mutex_job);

	pthread_mutex_destroy(&me->mutex);

	free(ptr);
	
	return 0;
}

